package com.nage.components;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import com.nage.components.collision.Collidable;
import com.nage.components.collision.CollisionManager;
import com.nage.components.collision.CollisionMask;
import com.nage.components.display.Background;
import com.nage.components.display.Shape;
import com.nage.components.display.Sprite;
import com.nage.components.display.TextBox;
import com.nage.components.movement.OnScreen;
import com.nage.components.movement.Physics;
import com.nage.components.movement.RandomMovement;
import com.nage.components.movement.RandomWaypointMovement;
import com.nage.components.movement.Tipping;
import com.nage.components.touch.AddSquareButton;
import com.nage.components.touch.Controllable;
import com.nage.components.touch.RemoveSquareButton;
import com.nage.components.touch.ToggleRandomMovement;
import com.nage.components.touch.menu.HostMultiplayerGame;
import com.nage.components.touch.menu.JoinMultiplayerGame;
import com.nage.components.touch.menu.StartSinglePlayer;
import com.nage.engine.GameGraphException;
import com.nage.engine.GameObject;


public abstract class Component {
	
	
	public static final int DEFAULT = 0;
	public static final int PHYSICS = 1;
	public static final int SHAPE = 2;
	public static final int RANDOM_MOVEMENT = 3;
	public static final int RANDOM_WAYPOINT_MOVEMENT = 4;
	public static final int COLLISION_MASK = 5;
	public static final int COLLIDABLE = 6;
	public static final int COLLISION_MANAGER = 7;
	public static final int BACKGROUND = 8;
	public static final int DRAWABLE = 9;
	public static final int TEXT_BOX = 10;
	public static final int ON_SCREEN = 11;
	public static final int ADD_SQUARE_BUTTON = 12;
	public static final int CONTROLLABLE = 13;
	public static final int REMOVE_SQAURE_BUTTON = 14;
	public static final int TOGGLE_RANDOM_MOVEMENT = 15;
	public static final int TOUCHABLE = 16;
	public static final int PONG_MOVEMENT_LEFT = 17;
	public static final int PONG_MOVEMENT_RIGHT = 18;
	public static final int PONG_BALL = 19;
	public static final int START_SINGLE_PLAYER = 20;
	public static final int HOST_MULTIPLAYER = 21;
	public static final int JOIN_MULTIPLAYER = 22;
	public static final int TIPPING = 23;
	public static final int SPRITE = 24;


	public int type = DEFAULT; // default component id - for components that don't do anything.
	public GameObject parent;
	
	/**
	 * Tracks whether this component has been updated so we know if it
	 * needs to be sent across the network on a multiplayer update.
	 */
	public boolean modified;
	
	/**
	 * Unique id for this component for synchronising on multiplayer system.
	 */
	public byte id;
	
	/**
	 * Assigned to a Component when it is created. Make sure this is incremented
	 * so that each Component has a unique id.
	 */
	private static byte next_id = 0x01;
	
	
	public Component(GameObject p) {
		parent = p;
		id = next_id++;
	}

	public abstract void update(long delta);

	public void status() {
		//Log.d("Component", "		status() id "+id+": "+parent.name+" x = "+parent.x+" y = "+parent.y);
	}

	public boolean flatten(ByteArrayOutputStream stream_builder) throws IOException {
		stream_builder.write(type);
		return true;
	}

	/**
	 * Creates a new component based on the type byte type. 
	 * @param type
	 * @return
	 * @throws GameGraphException 
	 */
	public static Component createComponent(byte type, GameObject obj) throws GameGraphException {
		switch ( type ) {
		case PHYSICS: return new Physics(obj);
		case SHAPE: return new Shape(obj);
		case RANDOM_MOVEMENT: return new RandomMovement(obj);
		case RANDOM_WAYPOINT_MOVEMENT: return new RandomWaypointMovement(obj);
		case COLLISION_MASK: return new CollisionMask(obj);
		case COLLIDABLE: return new Collidable(obj);
		case COLLISION_MANAGER: return CollisionManager.newCollisionManager(obj);
		case BACKGROUND: return new Background(obj);
		case TEXT_BOX: return new TextBox(obj);
		case ON_SCREEN: return new OnScreen(obj);
		case ADD_SQUARE_BUTTON: return new AddSquareButton(obj);
		case CONTROLLABLE: return new Controllable(obj);
		case REMOVE_SQAURE_BUTTON: return new RemoveSquareButton(obj);
		case TOGGLE_RANDOM_MOVEMENT: return new ToggleRandomMovement(obj);
		case START_SINGLE_PLAYER: return new StartSinglePlayer(obj);
		case HOST_MULTIPLAYER: return new HostMultiplayerGame(obj);
		case JOIN_MULTIPLAYER: return new JoinMultiplayerGame(obj);
		case TIPPING: return new Tipping(obj);
		case SPRITE: return new Sprite(obj, 1);
		case DEFAULT: throw new GameGraphException("DEFAULT component type. Cannot create specific component");
		default: throw new GameGraphException("UNKNOWN component type. Cannot create specific component");
		}
	}

	/**
	 * Read member variables from the byte array b and populate this object.
	 * @param b
	 * @param i
	 */
	public int expand(byte[] b, int i) {
		return i;
	}

	public String getType() {
		switch ( type ) {
		case PHYSICS: return "PHYSICS";
		case SHAPE: return "SHAPE";
		case RANDOM_MOVEMENT: return "RANDOM_MOVEMENT";
		case RANDOM_WAYPOINT_MOVEMENT: return "RANDOM_WAYPOINT_MOVEMENT";
		case COLLISION_MASK: return "COLLISION_MASK";
		case COLLIDABLE: return "COLLIDABLE";
		case COLLISION_MANAGER: return "COLLISION_MANAGER";
		case BACKGROUND: return "BACKGROUND";
		case TEXT_BOX: return "TEXT_BOX";
		case ON_SCREEN: return "ON_SCREEN";
		case ADD_SQUARE_BUTTON: return "ADD_SQUARE_BUTTON";
		case CONTROLLABLE: return "CONTROLLABLE";
		case REMOVE_SQAURE_BUTTON: return "REMOVE_SQUARE_BUTTON";
		case TOGGLE_RANDOM_MOVEMENT: return "TOGGLE_RANDOM_MOVEMENT";
		case START_SINGLE_PLAYER: return "START_SINGLE_PLAYER";
		case HOST_MULTIPLAYER: return "HOST_MULTIPLAYER";
		case JOIN_MULTIPLAYER: return "JOIN_MULTIPLAYER";
		case TIPPING: return "TIPPING";
		case SPRITE: return "SPRITE";
		case DEFAULT: return "DEFAULT";
		default: return "UNKNOWN";
		}
	}

	/**
	 * When writing a new component x, if you wish for it to have a reference to another
	 * Component y (ie. a game object must have both x and y to work), then override this
	 * method to call getComponent(int id) for each reference needed and check that they
	 * have been found.
	 * @return
	 * @throws GameGraphException 
	 */
	public boolean findLinks() throws GameGraphException {
		return true; 
	}


}
